//! 
//! 整型
//! 
//! 整型是数学中的整数。有符号之分（正负数的区别）,有符号是包含负数，无符号是正整数包含0。rust中内置的整型如下：
//! 
//! |长度|有符号类型|无符号类型|
//! |:---:|:---:|:---:|
//! |8位|i8|u8|
//! |16位|i16|u16|
//! |32位|i32|u32|
//! |64位|i64|u64|
//! |128位|i128|u128|
//! |size[^1]|isize|usize|
//! 
//! 有符号的数据以补码[^2]形式存在
//! 
//! ## 整型溢出
//! 
//! 溢出是指操作的数据结果出现超过当前整型最大值，rust中处理溢出规则如下：
//! 
//! - `--debug`: 编译器会检查是否存在溢出，如果存在，则使程序在编译时`panic`(崩溃,Rust使
//! 用这个术语来表明程序因错误而退出)。
//! - `--release`: Rust 不检测溢出。相反，当检测到整型溢出时，Rust会按照补码循环溢出[^3]
//! （two’s complement wrapping）的规则处理。 
//! 
//! 显示处理：
//! 
//! 要显式处理可能的溢出，可以使用标准库针对原始数字类型提供的这些方法：
//! 
//! - 使用‵wrapping_*`方法在所有模式下都按照补码循环溢出规则处理，例如`wrapping_add`
//! - 如果使用`checked_*`方法时发生溢出，则返回 None 值
//! - 使用`overflowing_*`方法返回该值和一个指示是否存在溢出的布尔值
//! - 使用`saturating_*`方法，可以限定计算后的结果不超过目标类型的最大值或低于最小值
//! 
//! [^1]: `isize`和`usize`类型取决于程序运行的计算机CPU类型：若CPU是32位的，则这两个类型是32位的，
//! 同理，若CPU是64位，那么它们则是64位。
//! [^2]: ^^补码
//! [^3]: 补码循环溢出: 大于该类型最大值的数值会被补码转换成该类型能够支持的对应数字的最小值。
//! 比如在 u8 的情况下，256 变成 0，257 变成 1，依此类推。程序不会 panic，但是该变量的值可能
//! 不是你期望的值。依赖这种默认行为的代码都应该被认为是错误的代码。
//! 

/// 溢出示例
///
/// 添加属性`#[allow(arithmetic_overflow)]`，否则会报如下错误：
/// 
/// ```log
/// error: this arithmetic operation will overflow
///   --> src/data_type/integer.rs:46:22
///    |
/// 46 |     println!("{:?}", a-1);
///    |                      ^^^ attempt to compute `0_u8 - 1_u8`, which would overflow
///    |
///    = note: `#[deny(arithmetic_overflow)]` on by default
/// ```
/// 
/// 打印结果是***255***。采用的是循环处理。
/// 
#[allow(arithmetic_overflow)]
pub fn overflowing_attr() {
    let a: u8 = 0;
    println!("{:?}", a-1);
}

/// 显式处理溢出
/// 
/// 通过`wrapping_sub`函数代替`#[allow(arithmetic_overflow)]`。得到结果任然是255
pub fn overflowing_wrapping() {
    let a: u8 = 0;
    println!("{:?}", a.wrapping_sub(1))
}

/// 显式处理溢出
/// 
/// ```rs
/// pub fn overflowing_demo() {
///    let a = 255_u8;
///     // overflowing_* 返回值是一个元组`(值， bool)`，如果溢出，bool为`true`。
///     assert_eq!(a.overflowing_add(1).0, 0);
///     assert_eq!(a.overflowing_add(1).1, true);
/// }
/// ```
/// 
/// ## Example
/// 
/// ```rust
/// use note::data_type::integer::overflowing_demo;
/// 
/// overflowing_demo();
/// ```
pub fn overflowing_demo() {
    let a = 255_u8;
    // overflowing_* 返回值是一个元组`(值， bool)`，如果溢出，bool为`true`。
    assert_eq!(a.overflowing_add(1).0, 0);
    assert_eq!(a.overflowing_add(1).1, true);
    // 溢出则为None
    assert_eq!(a.checked_add(1), None);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        overflowing_attr();
    }

    #[test]
    fn test1() {
        overflowing_wrapping();
    }

    #[test]
    fn test_overflowing_demo() {
        overflowing_demo();
    } 
}